/*-------------------------------------------------------------------------
 *
 * interrupt.c
 *	  中断处理例程。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/postmaster/interrupt.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <unistd.h>

#include "miscadmin.h"
#include "postmaster/interrupt.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/procsignal.h"
#include "utils/guc.h"
#include "utils/memutils.h"

volatile sig_atomic_t ConfigReloadPending = false;
volatile sig_atomic_t ShutdownRequestPending = false;

/*
 * 背景进程主循环的简单中断处理程序。
 */
void HandleMainLoopInterrupts(void)
{
	if (ProcSignalBarrierPending)
		ProcessProcSignalBarrier();

	if (ConfigReloadPending)
	{
		ConfigReloadPending = false;
		ProcessConfigFile(PGC_SIGHUP);
	}

	if (ShutdownRequestPending)
		proc_exit(0);

	/* 执行此进程的内存上下文日志记录 */
	if (LogMemoryContextPending)
		ProcessLogMemoryContextInterrupt();
}

/*
 * 触发配置重新加载的简单信号处理程序。
 *
 * 通常，这个处理程序会用于 SIGHUP。其理念是，使用它的代码
 * 将安排在主循环的方便位置检查 ConfigReloadPending 标志，
 * 或调用 HandleMainLoopInterrupts。
 */
void SignalHandlerForConfigReload(SIGNAL_ARGS)
{
	int			fc_save_errno = errno;

	ConfigReloadPending = true;
	SetLatch(MyLatch);

	errno = fc_save_errno;
}

/*
 * 作为故障退出的简单信号处理程序。
 *
 * 通常，这会用于处理 SIGQUIT。
 */
void SignalHandlerForCrashExit(SIGNAL_ARGS)
{
	/*
	 * 我们不希望运行 proc_exit() 或 atexit() 回调 -- 我们在这里
	 * 是因为共享内存可能已经损坏，所以我们不想尝试
	 * 清理我们的事务。只需把窗户钉死，然后离开这个地方。
	 * 回调从信号处理程序中运行也是不安全的。
	 *
	 * 请注意，我们使用 _exit(2) 而不是 _exit(0)。这是为了强迫
	 * 后台工作进程进入系统重置循环，如果有人向随机的
	 * 后端发送手动 SIGQUIT。这是必要的，正因为如此我们没有
	 * 清理我们的共享内存状态。（pmsignal.c 中的 "死人开关"
	 * 机制应该确保后台工作进程也将此视为故障，但反正
	 * 重复确认也没有坏处。）
	 */
	_exit(2);
}

/*
 * 触发长时间运行的后台进程关闭并退出的简单信号处理程序。
 *
 * 通常，这个处理程序会用于 SIGTERM，但一些进程使用
 * 其他信号。特别是，检查点进程在 SIGUSR2 上退出，
 * 而 WAL 写入器在 SIGINT 或 SIGTERM 上退出。
 *
 * ShutDownRequestPending 应在主循环中的方便位置进行检查，
 * 否则主循环应该调用 HandleMainLoopInterrupts。
 */
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
{
	int			fc_save_errno = errno;

	ShutdownRequestPending = true;
	SetLatch(MyLatch);

	errno = fc_save_errno;
}
